#include <bitset>
#include <cmath>
#include <queue>
#include "agentModAddLeaf.h"

using namespace std;

void agentModAddLeaf::run()
{
    solution* parent = thePool->getRandomSolution();

    solution* child = new solution(parent);

    // Get Random Node
    assert(child->getRoot() != NULL);
    vector<pair<node *, string> > candidates;
    queue<pair<node *,string> > nodeQ;
    nodeQ.push(make_pair(child->getRoot(),""));
    while(!nodeQ.empty())
    {
        node* tmp = nodeQ.front().first;
        string path = nodeQ.front().second;
        nodeQ.pop();

        if (tmp->getLeft() == NULL)
        {
            candidates.push_back(make_pair(tmp, path + "l"));
        }
        if (tmp->getRight() == NULL)
        {
            candidates.push_back(make_pair(tmp, path + "r"));
        }
         
        if (tmp->getLeft() != NULL) nodeQ.push(make_pair(tmp->getLeft(), path + "l"));
        if (tmp->getRight() != NULL) nodeQ.push(make_pair(tmp->getRight(),path + "r"));
    }

    
    if (candidates.size() == 0)
    {
        delete child;
        return;
    }
    int ndx = rand() % candidates.size();


    // Find records to train on
    bitset<TRAIN_RECORD_COUNT> records;
    records.set();

    for (int j = 0; j < TRAIN_RECORD_COUNT; j++)
    {
        record* tmpRecord = thePool->getTrainingSet()->getNthRecord(j);
        for(int i = 0; i < candidates[ndx].second.size() && records[i]; i++)
        {
            bool left = candidates[i].first->evaluatesLeft(tmpRecord);
            if ((left && candidates[ndx].second[i] != 'l') ||
                (!left && candidates[ndx].second[i] != 'r'))
               records.reset(i);
        }
    }


    if (candidates[ndx].second[candidates[ndx].second.size()-1] == 'l')
        candidates[ndx].first->setLeft(determineSplit(&records));
    else
        candidates[ndx].first->setRight(determineSplit(&records));

    insert(child, parent);
}
